package com.jxpanda.commons.encrypt;

import com.jxpanda.commons.key.RSAKeyHelper;
import com.jxpanda.commons.signature.Signature;
import com.jxpanda.commons.signature.SignatureAlgorithm;
import com.jxpanda.commons.toolkit.Base64Kit;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * @author Panda
 */
@Slf4j
@Getter
@SuppressWarnings("AlibabaClassNamingShouldBeCamel")
public class RSA extends AbstractEncrypt.Asymmetric {

    /**
     * 默认用2048位
     */
    public static final int DEFAULT_KEY_SIZE = 2048;

    private final int keySize;

    public RSA() {
        this(DEFAULT_KEY_SIZE);
    }

    public RSA(int keySize) {
        super(EncryptAlgorithm.RSA);
        this.keySize = keySize == 0 ? DEFAULT_KEY_SIZE : keySize;
        this.keyPair = generateKeyPair(this.getKeySize());
    }

    public RSA(int keySize, KeyPair keyPair) {
        super(EncryptAlgorithm.RSA);
        this.keySize = keySize == 0 ? DEFAULT_KEY_SIZE : keySize;
        this.keyPair = keyPair;
    }

    public static KeyPair generateKeyPair(int keySize) {
        return new RSAKeyHelper(keySize).generateKeyPair();
    }

    /**
     * RSA加密
     */
    @Override
    public String encrypt(String content) {
        var encryptSize = keySize == 1024 ? 117 : (keySize / 8);
        byte[] bytes = sectionFunction(content.getBytes(StandardCharsets.UTF_8), this.getEncoder(), encryptSize);
        return new String(bytes, StandardCharsets.UTF_8);
    }

    /**
     * RSA解密
     */
    @Override
    public String decrypt(String content) {
        var decryptSize = keySize / 8;
        byte[] bytes = sectionFunction(content.getBytes(StandardCharsets.UTF_8), this.getDecoder(), decryptSize);
        return new String(bytes);
    }

    /**
     * 私钥签名，默认是用SHA256withRSA算法
     */
    public static byte[] signature(String content, PrivateKey privateKey) {
        return Signature.signature(content, privateKey, SignatureAlgorithm.SHA256_WITH_RSA);
    }


    /**
     * 公钥验签，默认用SHA256withRSA算法
     */
    public static boolean verify(String content, byte[] sign, PublicKey publicKey) {
        return Signature.verify(content, sign, publicKey, SignatureAlgorithm.SHA256_WITH_RSA);
    }


    /**
     * 加密、解密的分段处理函数
     */
    private byte[] sectionFunction(byte[] bytes, Cipher cipher, int sectionLength) {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            int size = bytes.length;
            byte[] buffer;
            int offset = 0;
            while (size - offset > 0) {
                if (size - offset >= sectionLength) {
                    buffer = cipher.doFinal(bytes, offset, sectionLength);
                } else {
                    buffer = cipher.doFinal(bytes, offset, size - offset);
                }
                bos.write(buffer);
                offset += sectionLength;
            }
            return bos.toByteArray();
        } catch (Exception ex) {
            log.error("[SECTION FUNCTION ERROR]", ex);
        }
        return new byte[0];
    }

}
